//
// Created by LiuYou on 2021/5/7.
//

#define _GNU_SOURCE 1

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cassert>
#include <unistd.h>
#include <sys/poll.h>
#include <fcntl.h>


int main(int argc, char** argv) {
    if (argc < 4) {
        std::fprintf(stderr, "用法: %s ip地址 端口号 用户名\n", basename(argv[0]));
        return -1;
    }
    const char* const ip = argv[1];
    int port = std::atoi(argv[2]);
    const char* const userName = argv[3];

    struct sockaddr_in serverSockAddrIn{
            .sin_family=PF_INET,
            .sin_port=htons(port),
            {.s_addr=0}
    };
    inet_pton(AF_INET, ip, &serverSockAddrIn.sin_addr);

    int sockFD = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockFD >= 0);

    if (connect(sockFD, (sockaddr*) &serverSockAddrIn, sizeof(serverSockAddrIn)) < 0) {
        std::perror("connect()");
        close(sockFD);
        return -1;
    }

    // TODO 私聊:
    //  先发送用户名到Server
    send(sockFD, userName, std::strlen(userName), 0);


    // 监听标准输入和sockFD上发生的可读、可写和异常等事件。
    pollfd pollFDS[2]{
            {.fd=0,
                    // 监听 0 是否有数据可读。
                    .events=POLLIN, .revents=0},
            {.fd=sockFD,
                    // 监听 sockFD 是否有数据可读或者tcp连接是否被server关闭
                    .events=POLLIN | POLLRDHUP, .revents=0}
    };

    const int BUF_SIZE = 64;
    char readBuf[BUF_SIZE]{};
    int pipeFD[2];
    int ret = pipe(pipeFD);
    assert(ret != -1);

    for (;;) {
        ret = poll(pollFDS, sizeof(pollFDS), -1);
        if (ret < 0) {
            std::fprintf(stderr, "poll()调用失败\n");
            break;
        }

        if (pollFDS[1].revents & POLLRDHUP) {
            std::fprintf(stderr, "服务端关闭了连接\n");
            break;
        } else if (pollFDS[1].revents & POLLIN) {
            std::memset(readBuf, '\0', sizeof(readBuf));
            recv(pollFDS[1].fd, readBuf, sizeof(readBuf) - 1, 0);
            // 接受的数据:
            std::fprintf(stdout, "%s\n", readBuf);
        }

        if (pollFDS[0].revents & POLLIN) {
            splice(pollFDS[0].fd, NULL, pipeFD[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
            // 将从 0 输入的数据移动到 sockFD。
            splice(pipeFD[0], NULL, pollFDS[1].fd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
        }

    }


    return 0;
}